﻿using SharPy.Common;
using SharPy.GameObjects;
using SharPy.GameSettings;
using SharPy.Interface;
using SharPy.Parser;
using SharPy.Parser.clCommands;
using System;
using Windows.Media;
using Windows.Storage;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace SharPy
{
    public partial class GamePage
    {
        public Color defaultTextColor = new Color();
        public clGame CurrentGame;

        private NavigationHelper navigationHelper;
        private ObservableDictionary defaultViewModel = new ObservableDictionary();
        internal Windows.UI.Xaml.Media.Animation.Storyboard AnimationStoryboard;
        private clGameInterfaceHelper InterfaceHelper;

        SystemMediaTransportControls systemControls;

        #region PageInitialization

        void InitPage()
        {
            this.navigationHelper = new NavigationHelper(this);
            this.navigationHelper.LoadState += navigationHelper_LoadState;
            this.navigationHelper.SaveState += navigationHelper_SaveState;

            this.InterfaceHelper = new clGameInterfaceHelper(this);

            InitializeTransportControls();
        }

        private async void Page_Loaded(object sender, RoutedEventArgs e)
        {
            foreach (string setting in SharPy.GameSettings.clSettings.GameSettings.Keys)
            {
                this.defaultViewModel[setting] = SharPy.GameSettings.clSettings.GameSettings[setting];
            }

            if (clText.IsInitialized)
            {
                if (CurrentGame.LineNoHolder != 0)
                {
                    await this.InterfaceHelper.LoadGame(this, CurrentGame);
                }
                return;
            }

            try
            {
                string fileContent = await FileIO.ReadTextAsync(CurrentGame.ScriptFile, Windows.Storage.Streams.UnicodeEncoding.Utf8);

                //Try to get text from file
                if (await clText.fillText(CurrentGame.ScriptFile) == 1)
                {
                }
                else
                {
                    endGame("Some kind of error reading file.");
                }
            }
            catch (ArgumentOutOfRangeException)
            {
                endGame("There seems to be error with game encoding. Please ensure text is encoded in UTF-8.");
            }
            catch (Exception ex)
            {
                endGame();
            }
        }

        public ObservableDictionary DefaultViewModel
        {
            get { return this.defaultViewModel; }
        }


        #region NavigationHelper registration

        public NavigationHelper NavigationHelper
        {
            get { return this.navigationHelper; }
        }
        private void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
        {
        }
        private void navigationHelper_SaveState(object sender, SaveStateEventArgs e)
        {
        }
        private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
        {
        }


        private void NavigationHelper_SaveState(object sender, SaveStateEventArgs e)
        {
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            this.navigationHelper.OnNavigatedTo(e);

            if (e.Parameter.GetType() == typeof(clGame))
                this.CurrentGame = e.Parameter as clGame;
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            this.navigationHelper.OnNavigatedFrom(e);
        }

        #endregion

        #region musicPlayback
        void MusicPlayer_CurrentStateChanged(object sender, RoutedEventArgs e)
        {
            switch (backgroundMusic.CurrentState)
            {
                case MediaElementState.Playing:
                    systemControls.PlaybackStatus = MediaPlaybackStatus.Playing;
                    break;
                case MediaElementState.Paused:
                    systemControls.PlaybackStatus = MediaPlaybackStatus.Paused;
                    break;
                case MediaElementState.Stopped:
                    systemControls.PlaybackStatus = MediaPlaybackStatus.Stopped;
                    break;
                case MediaElementState.Closed:
                    systemControls.PlaybackStatus = MediaPlaybackStatus.Closed;
                    break;
                default:
                    break;
            }
        }


        void SystemControls_ButtonPressed(SystemMediaTransportControls sender,
                    SystemMediaTransportControlsButtonPressedEventArgs args)
        {
            switch (args.Button)
            {
                case SystemMediaTransportControlsButton.Play:
                    clMusic.PlayMedia(backgroundMusic, this);
                    break;
                case SystemMediaTransportControlsButton.Pause:
                    clMusic.PauseMedia(backgroundMusic, this);
                    break;
                default:
                    break;
            }
        }
        void InitializeTransportControls()
        {
            // Hook up app to system transport controls.
            systemControls = SystemMediaTransportControls.GetForCurrentView();
            systemControls.ButtonPressed += SystemControls_ButtonPressed;

            // Register to handle the following system transpot control buttons.
            systemControls.IsPlayEnabled = true;
            systemControls.IsPauseEnabled = true;
        }
        private void backgroundMusic_MediaFailed(object sender, ExceptionRoutedEventArgs e)
        {
            clDialogs.Error(e.ErrorMessage);
        }

        #endregion

        #endregion

        #region Buttons
        private async void Quit_Click(object sender, RoutedEventArgs e)
        {
            if (await clDialogs.QuitGame())
            {
                clSettings.saveGameState(CurrentGame.LineNoHolder);
                Frame.GoBack();
            }
        }

        private void Save_Click(object sender, RoutedEventArgs e)
        {
            Frame.Navigate(typeof(SavePage), CurrentGame);
        }

        private void Load_Click(object sender, RoutedEventArgs e)
        {
            Frame.Navigate(typeof(LoadPage), CurrentGame);
        }

        private void Skip_Click(object sender, RoutedEventArgs e)
        {

        }
        private void History_Click(object sender, RoutedEventArgs e)
        {
            Frame.Navigate(typeof(HistoryPage), CurrentGame);
        }
        #endregion

        #region GameEvents
        private void SetSetting(object sender, GameSettings.SettingChanged e)
        {
            this.defaultViewModel[e.Key] = e.Value;
        }
        private async void endGame(string reason = "-1")
        {
            clMusic.PauseMedia(backgroundMusic, this);
            if (reason != "-1")
            {
                await clDialogs.Error(reason);
            }
            InterfaceHelper.ClearScreen(this);

            Frame.Navigate(typeof(MainPage));
        }
        #endregion

        internal async void sMainText_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            //TODO: remove, change to actual data binding
            //applySettings();

            clCommand objCom = new clCommand();
            string s;
            int bStop = 0;

            while (bStop == 0)
            {
                if ((s = clText.getLine(CurrentGame.LineNoHolder)) != null)
                    objCom = clParser.lineMatch(s);
                else
                {
                    objCom.sName = clCommand.Name.EndGame;
                }
                bStop = await CommandHandle(objCom);
                CurrentGame.LineNoHolder++;
                clText.gameState = CurrentGame.LineNoHolder;
            }

            if (bStop == -1)
                endGame();
        }

        /// <summary>
        /// Handling incoming command
        /// </summary>
        /// <param name="objCom"></param>
        /// <returns></returns>
        internal async System.Threading.Tasks.Task<int> CommandHandle(clCommand objCom)
        {
            switch (objCom.sName)
            {
                case clCommand.Name.Comment:
                    break;

                case clCommand.Name.SetBackground:
                    return await SetBackground.CommandHandle(objCom, this);

                case clCommand.Name.ShowText:
                    return await ShowText.CommandHandle(objCom, this);

                case clCommand.Name.ShowImage:
                    return await ShowImage.CommandHandle(objCom, this);

                case clCommand.Name.ShowMenu:
                    await SharPy.GameMenu.clMenuClass.buildMenu(CurrentGame.LineNoHolder);
                    await showMenu();
                    return 1;

                case clCommand.Name.ShowNVL:
                    Windows.UI.Popups.MessageDialog md = new Windows.UI.Popups.MessageDialog("NVL Mode not implemented");
                    md.ShowAsync();
                    break;

                case clCommand.Name.HideImage:
                    return await HideImage.CommandHandle(objCom, this);

                case clCommand.Name.ScreenAnimation:
                    clAnimations.AnimatePage(this, objCom.sParameter[0]);
                    break;

                case clCommand.Name.JumpToLabel:
                    CurrentGame.LineNoHolder = clText.findLabel(objCom.sParameter[0]);
                    break;

                case clCommand.Name.PlayMusic:
                    clMusic.CommandHandle(objCom, this);
                    break;

                case clCommand.Name.StopMusic:
                    clMusic.CommandHandle(objCom, this);
                    break;

                case clCommand.Name.EndGame:
                    return -1;

                default:
                    break;
            }
            return 0;
        }
        /// <summary>
        /// Shows a menu
        /// </summary>
        /// <param name="pMenu"></param>
        /// <returns></returns>
        private async System.Threading.Tasks.Task<clCommand> showMenu()
        {
            ListBox lb = new ListBox();
            lb.Name = "ActiveMenu";
            lb.Height = 100 * SharPy.GameMenu.clMenuClass.optList.Count + 10;
            lb.Width = 400;
            lb.SelectionChanged += new SelectionChangedEventHandler(this.MenuPressed);
            foreach (SharPy.GameMenu.clMenuOption opt in SharPy.GameMenu.clMenuClass.optList)
            {
                ListBoxItem lbi = new ListBoxItem();
                lbi.FontSize = SharPy.GameSettings.clSettings.GetSetting("FontSize");
                lb.Items.Add(lbi);
                lbi.Height = 100;
                lbi.Content = opt.sName;
            }

            gridMain.Children.Add(lb);
            InterfaceHelper.blockInterface(true);
            lb.Visibility = Windows.UI.Xaml.Visibility.Visible;
            lb.SetValue(Canvas.ZIndexProperty, 999);
            return null;
        }

        /// <summary>
        /// Handler for a menu choice
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuPressed(object sender, RoutedEventArgs e)
        {
            ListBox box = sender as ListBox;

            switch (SharPy.GameMenu.clMenuClass.optList[box.SelectedIndex].objCommand.sName)
            {
                case clCommand.Name.JumpToLabel:
                    CurrentGame.LineNoHolder = clText.findLabel(SharPy.GameMenu.clMenuClass.optList[box.SelectedIndex].objCommand.sParameter[0]);
                    break;
                case clCommand.Name.JumpToLine:
                    CurrentGame.LineNoHolder = Convert.ToInt32(SharPy.GameMenu.clMenuClass.optList[box.SelectedIndex].objCommand.sParameter[0]);
                    break;
                default:
                    throw new NotSupportedException();
            }

            gridMain.Children.Remove(box);
            InterfaceHelper.blockInterface(false);
        }
    }
}